/*
 * Copyright (c) csii.com.cn 2016 zhaojin
 */

package com.csii.ssm.controller;

import com.csii.ssm.common.Dict;
import com.csii.ssm.core.CommonDict;
import com.csii.ssm.dto.*;
import com.csii.ssm.exception.AccessRuntimeException;
import com.csii.ssm.exception.AccessRuntimeExceptionDict;
import com.csii.ssm.listener.SystemSessionContext;
import com.csii.ssm.model.Order;
import com.csii.ssm.model.User;
import com.csii.ssm.secure.CertificateCoder;
import com.csii.ssm.secure.DESedeCoder;
import com.csii.ssm.service.IPjnlService;
import com.csii.ssm.service.IUserService;
import com.csii.ssm.util.CommonUtil;
import com.csii.ssm.util.JsonUtil;
import org.dom4j.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.ServletContextAware;

import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * 公共交易控制器
 *
 * @author zhaojin 15398699939@163.com
 * @create 2016-08-12-08:59
 */
@Controller
public class PublicController extends BaseController implements ServletContextAware {

    private static final Logger logger = LoggerFactory.getLogger(PublicController.class);

    @Inject
    private IUserService userService;

    @Inject
    private IPjnlService pjnlService;

    @Inject
    public AccessTokenManager accessTokenManager;

    @Inject
    public ResubmitTokenManager resubmitTokenManager;

    @Value("#{mvcContext['auth.certificatePath']}")
    private String certificatePath;

    @Value("#{mvcContext['auth.keyStorePath']}")
    private String keyStorePath;

    @Value("#{mvcContext['auth.alias']}")
    private String alias;

    @Value("#{mvcContext['auth.password']}")
    private String password;

    @Value("#{mvcContext['auth.desKey']}")
    private String desKey;


    @Value("#{mvcContext['auth.redirectUrl']}")
    private String redirectUrl;

    private ServletContext servletContext;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index() {
        logger.debug("invoke index>>>");
        return "index";
    }

    @RequestMapping(value = "/404", method = RequestMethod.GET)
    public String _404() {
        logger.debug("invoke 404>>>");
        return "404";
    }

    @RequestMapping(value = "/500", method = RequestMethod.GET)
    public String _500(@RequestParam(required = false) String errmsg, @RequestParam(required = false) String errcode, Model model) {
        logger.debug("invoke 500>>>");
        model.addAttribute(ERRMSG, errmsg);
        model.addAttribute(ERRCODE, errcode);
        return "500";
    }

    @RequestMapping(value = "/error", method = RequestMethod.GET)
    public String error(@RequestParam String errorMsg, HttpServletRequest request) {
        request.setAttribute(CommonDict.ERROR_MSG, errorMsg);
        return TRANSCODE_500;
    }

    @RequestMapping(value = "generateAccessToken", method = RequestMethod.GET)
    public void generateAccessToken(@RequestParam String appid, @RequestParam String secret, Model model) {
        logger.debug("generateToken req merSecret>>>", secret);
        //TODO:
        if (appid.equals("TIANHONG_APPID") && secret.equals("TIANHONG_SECRET")) {
            Token token = accessTokenManager.createToken(servletContext);
            model.addAttribute(CommonDict.RES, getAjaxData().put(CommonDict.ACCESS_TOKEN, token));
        } else {
            throw new AccessRuntimeException(AccessRuntimeExceptionDict.ERROR_GENERATEACCESSTOKEN);
        }
    }

    @RequestMapping(value = "getAccessSecretKey", method = RequestMethod.GET)
    public void getAccessSecretKey(@RequestParam String encryptUniqueID, Model model) {
        try {
            // 私钥解密
            byte[] decrypt = CertificateCoder.decryptByPrivateKey(CommonUtil.decodeHex(encryptUniqueID),
                    keyStorePath, alias, password);
            String tokenUniqueID = new String(decrypt);
            accessTokenManager.verifyToken(servletContext, tokenUniqueID);
            // 私钥加密
            byte[] encodedKey = CertificateCoder.encryptByPrivateKey(CommonUtil.decodeHex(desKey), keyStorePath, alias, password);
            String encodedKeyStr = CommonUtil.encodeHexString(encodedKey);
            logger.debug("支付前置返回密钥密文给商城:{} 密钥::{}", encodedKeyStr, desKey);
            model.addAttribute(CommonDict.RES, getAjaxData().put(CommonDict.KEY, encodedKeyStr));
        } catch (AccessRuntimeException e) {
            throw new AccessRuntimeException(e.getMessage(), e);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AccessRuntimeException(AccessRuntimeExceptionDict.ERROR_GETACCESSSECRETKEY);
        }
    }

    @RequestMapping(value = "getAccessLoginURI", method = RequestMethod.POST)
    public void getAccessLoginURI(@RequestParam String userEncryptData, Model model, HttpSession httpSession) {
        // 支付前台解密用户数据
        try {
            byte[] outputData = DESedeCoder.decrypt(CommonUtil.decodeHex(userEncryptData), CommonUtil.decodeHex(desKey));
            String userData = new String(outputData);
            PainObj painObj = JsonUtil.json2obj(userData, PainObj.class);
            User user = painObj.getUser();
            httpSession.setAttribute(Dict.LOGINUSER, user);
            if (painObj.getOrder() != null) {
                Order order = painObj.getOrder();
                httpSession.setAttribute(Dict.PAYORDER, order);
            }
            logger.debug("painObj成功解析成对象 str:{}", JsonUtil.obj2json(painObj));
            logger.debug("sdk sid:{} , s:{}", httpSession.getId(), httpSession.toString());
            logger.debug("sdk seseion:user {}", JsonUtil.obj2json(httpSession.getAttribute(Dict.LOGINUSER)));
            model.addAttribute(CommonDict.RES, getAjaxData().put(CommonDict.REDIRECT_URL, redirectUrl + httpSession.getId()));
        } catch (AccessRuntimeException e) {
            throw new AccessRuntimeException(e.getMessage(), e);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AccessRuntimeException(AccessRuntimeExceptionDict.ERROR_GETACCESSLOGINURI);
        }
    }

    /**
     *
     * @param uEncryptData 用户加密信息
     * @param oEncryptData 订单信息base64编码
     * @param tEncryptData  交易码
     * @param uniEncryptData Uniqueid加密信息
     * @param model
     * @param httpSession
     */
    @RequestMapping(value = "getAccessLoginURLIOS", method = RequestMethod.POST)
    public void getAccessLoginURLIOS(@RequestParam String uEncryptData, @RequestParam String oEncryptData,
                                     @RequestParam String tEncryptData, @RequestParam String uniEncryptData,
                                     Model model, HttpSession httpSession) {
        try {
            //先验证tokenId
            // 私钥解密tokenid
            byte[] unidecrypt = CertificateCoder.decryptByPrivateKey(CommonUtil.decodeHex(uniEncryptData),keyStorePath, alias, password);
            accessTokenManager.verifyToken(servletContext, new String(unidecrypt));
            // 私钥解密用户信息
            byte[] udecrypt = CertificateCoder.decryptByPrivateKey(CommonUtil.decodeHex(uEncryptData),keyStorePath, alias, password);
            User user = JsonUtil.json2obj(new String(udecrypt),User.class);
            httpSession.setAttribute(Dict.LOGINUSER, user);
            logger.debug("User {}",JsonUtil.obj2json(user));
            Order order = null;
            if (oEncryptData != null) {
                order = JsonUtil.json2obj(CommonUtil.decodeBase64String(oEncryptData.getBytes()),Order.class);
                logger.debug("Order {}",JsonUtil.obj2json(order));
                httpSession.setAttribute(Dict.PAYORDER, order);
            }
            model.addAttribute(CommonDict.RES, getAjaxData());
        } catch (AccessRuntimeException e) {
            throw new AccessRuntimeException(e.getMessage(), e);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AccessRuntimeException(AccessRuntimeExceptionDict.ERROR_GETACCESSLOGINURI);
        }
    }


    @RequestMapping(value = "accessLogin", method = RequestMethod.POST)
    public void accessLogin(@RequestParam String signature, Model model, HttpSession httpSession) {
        // 支付前台解密用户数据
        try {
            HttpSession sdkSession = SystemSessionContext.getSession(signature);
            logger.debug("accessLogin sid:{} , s:{}", sdkSession.getId(), sdkSession.toString());
            logger.debug("accessLogin seseion:user {}", JsonUtil.obj2json(sdkSession.getAttribute(Dict.LOGINUSER)));
            User user = (User) sdkSession.getAttribute(Dict.LOGINUSER);
            httpSession.setAttribute(Dict.LOGINUSER, user);
            String loginType = Dict.LOGINTYPE_AUTH;
            Map resMap = new HashMap();
            resMap.put(Dict.LOGINUSER, user);
            if (sdkSession.getAttribute(Dict.PAYORDER) != null) {
                Order order = (Order) sdkSession.getAttribute(Dict.PAYORDER);
                httpSession.setAttribute(Dict.PAYORDER, order);
                loginType = Dict.LOGINTYPE_PAY;
                resMap.put(Dict.PAYORDER, order);
            }
            resMap.put(Dict.LOGINTYPE, loginType);//前台按照登录类型（授权登录，支付）跳转页面处理逻辑
            AjaxData ajaxData = getAjaxData();
            ajaxData.setDataMap(resMap);
            model.addAttribute(CommonDict.RES, ajaxData);
        } catch (AccessRuntimeException e) {
            throw new AccessRuntimeException(e.getMessage(), e);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AccessRuntimeException(AccessRuntimeExceptionDict.ERROR_GETACCESSLOGINURI);
        }
    }

    @RequestMapping(value = "closePayFunPre", method = RequestMethod.GET)
    public void closePayFunPre(@RequestParam(required = false) String commPwd, @RequestParam(required = false) String smsCode, Model model) {
        model.addAttribute(CommonDict.RES, getAjaxData().put(CommonDict.REDIRECT_URL, "http://localhost:8080/payment-access/"));
    }

    @RequestMapping(value = "genToken", method = RequestMethod.GET)
    public void getSmsToken(Model model, HttpSession httpSession) {
        try {
            Token token = resubmitTokenManager.createToken(httpSession);
            model.addAttribute(CommonDict.RES, getAjaxData().put(CommonDict.RESUBMIT_TOKEN, token));
        } catch (Exception e) {
            throw new AccessRuntimeException(AccessRuntimeExceptionDict.ERROR_GEN_RESUBMIT_TOKEN);
        }
    }

    @RequestMapping(value = "simLoginUser", method = RequestMethod.POST)
    public void loginUser(@RequestParam String tel, Model model, HttpServletRequest request) {
        User u = userService.loadByTel(tel);
        AjaxData ajaxData = getAjaxData();
        ajaxData.put("user", u);
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute(Dict.LOGINUSER, u);
        model.addAttribute(CommonDict.RES, ajaxData);
    }

    //TODO:test
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public void login(@ModelAttribute User user, @ModelAttribute TokenImpl token, Model model, HttpSession httpSession) {
        logger.debug("login {} {}", user, token);
        resubmitTokenManager.verifyToken(httpSession, token);
        User u = userService.loginBy(user);
        AjaxData ajaxData = getAjaxData();
        ajaxData.put("user", u);
        httpSession.setAttribute(Dict.LOGINUSER, u);
        model.addAttribute(CommonDict.RES, ajaxData);
    }


    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
}
